﻿using GalaSoft.MvvmLight;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static GMap.NET.Entity.OpenStreetMapGraphHopperRouteEntity;
using GMap.NET.WindowsForms;
using GMap.NET;
using GMapMarkerExt.Markers;
using System.Reflection;
using System.IO;
using System.Threading;
using CsvHelper;
using System.Collections;
using System.Globalization;

namespace RailYardManager
{
    public partial class MainForm : Form
    {
        private MainFormViewModel _vm;

        public MainForm()
        {
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.AllPaintingInWmPaint, true);
            this.UpdateStyles();
            InitializeComponent();
            SetDataGridViewDoubleBuffered(this.dataGridView1);
            _vm = new MainFormViewModel();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            this.bindingSource1.DataSource = _vm.Yards;

            _vm.OnScanFinished += ViewModel_OnScanFinished;
        }

        private void ViewModel_OnScanFinished(object sender, EventArgs e)
        {
            Draw_Yard_Click(null,null); 
        }

        private void MainForm_Shown(object sender, EventArgs e)
        {
            InitMap();
            gMapControl1.MapProvider = GMap.NET.MapProviders.BingOSMapProvider.Instance;
            GMaps.Instance.Mode = AccessMode.ServerAndCache;
            this.gMapControl1.DragButton = MouseButtons.Right;
            this.gMapControl1.Position = new PointLatLng(40.880631, -96.880768);
            this.gMapControl1.MouseWheelZoomEnabled = true;
            this.gMapControl1.MouseWheelZoomType = MouseWheelZoomType.MousePositionWithoutCenter;
            this.gMapControl1.ShowCenter = true;
            gMapControl1.Refresh();
        }
        private void MenuItem_Scan_Click(object sender, EventArgs e)
        {
            System.Windows.Forms.FolderBrowserDialog dialog = new System.Windows.Forms.FolderBrowserDialog();
            dialog.Description = "Please select the folder.";
            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                if (!string.IsNullOrEmpty(dialog.SelectedPath))
                {
                    _vm.ScanDir(dialog.SelectedPath);
                }
            }
        }

        #region Map Toolbox
        private void Zoom_In_Click(object sender, EventArgs e)
        {
            this.gMapControl1.Zoom += 1;
        }
        private void Zoom_Out_Click(object sender, EventArgs e)
        {
            this.gMapControl1.Zoom -= 1;
        }
        private void Map_Bear_Left_Click(object sender, EventArgs e)
        {
            this.gMapControl1.Bearing -= 10;
        }
        private void Map_Bear_Right_Click(object sender, EventArgs e)
        {
            this.gMapControl1.Bearing += 10;
        }

        private GMapOverlay nodeLayer;
        private GMapOverlay osmLayer;
        private void InitMap()
        {
            this.gMapControl1.Overlays.Clear();

            //创建Node图层
            nodeLayer = new GMapOverlay("Mark");

            osmLayer = new GMapOverlay("OSM");


            this.gMapControl1.Overlays.Add(osmLayer);

            //将图层添加到地图
            this.gMapControl1.Overlays.Add(nodeLayer);
        }

        private void Draw_Yard_Click(object sender, EventArgs e)
        {
            nodeLayer.Clear();
            //DrawYard(this._vm.CurYard);
            foreach(var y in _vm.Yards)
            {
                GMapMarkerCircle marker = new GMapMarkerCircle(new PointLatLng(y.Latitude, y.Longitude));
                marker.Fill = new SolidBrush(Color.Yellow);
                marker.Name = y.Name?.ToString();
                marker.ToolTipText = y.Name !=null ? y.Name.ToString() : "Unnamed Yard";
                marker.ToolTip.Fill = new SolidBrush(Color.FromArgb(100, Color.Black));
                marker.ToolTip.Foreground = Brushes.White;
                marker.ToolTip.TextPadding = new Size(20, 20);
                //将标记添加到图层
                nodeLayer.Markers.Add(marker);
            }
        }
        private void DrawYard(Yard y)
        {
            if (y == null) return;
            foreach (var c in y.Connections)
            {
                DrawConnection(y, c);
            }
            foreach (var p in y.Points)
            {
                DrawNode(p);
            }
            DrawPolygon(y.Boundary);
            foreach (var sub in y.Yards)
            {
                DrawYard(sub);
            }
        }
        private void DrawNode(YPoint p)
        {
            //创建“marker”标记，设置其位于40.0，117.0，及箭头样式
            GMapMarkerCircle marker = new GMapMarkerCircle(new PointLatLng(p.Latitude, p.Longitude));
            if (p.Type == YPointType.gate_in || p.Type == YPointType.gate_out)
            {
                marker.Fill = new SolidBrush(Color.DarkGreen);
            }
            else
            {
                marker.Fill = new SolidBrush(Color.Yellow);
            }
            marker.Name = p.ToString();
            marker.ToolTipText = p.ToString();
            marker.ToolTip.Fill = new SolidBrush(Color.FromArgb(100, Color.Black));
            marker.ToolTip.Foreground = Brushes.White;
            marker.ToolTip.TextPadding = new Size(20, 20);
            //将标记添加到图层
            nodeLayer.Markers.Add(marker);
        }
        private void DrawConnection(Yard y, Connection c)
        {
            var p1 = y.GetPointById(c.FromPointId);// y.Points.FirstOrDefault(i => i.Id == c.FromPointId);
            var p2 = y.GetPointById(c.ToPointId); //y.Points.FirstOrDefault(i => i.Id == c.ToPointId);

            if (p1 == null || p2 == null) return;

            GMapRoute route1 = new GMapRoute("route1");
            if (c.Type == YConnectionType.bridge)  //设置route的颜色和粗细
            {
                route1.Stroke = new Pen(Color.Blue, 5);
            }
            else
            {
                route1.Stroke = new Pen(Color.Black, 5);
            }

            //向route中添加点
            route1.Points.Add(new PointLatLng(p1.Latitude, p1.Longitude));
            route1.Points.Add(new PointLatLng(p2.Latitude, p2.Longitude));
            //将route添加到图层
            nodeLayer.Routes.Add(route1);
        }
        private void DrawPolygon(IEnumerable<BoundaryPoint> points)
        {
            List<PointLatLng> temp = new List<PointLatLng>();
            foreach (var p in points)
            {
                temp.Add(new PointLatLng(p.Latitude, p.Longitude));
                GMapMarkerCircle marker = new GMapMarkerCircle(new PointLatLng(p.Latitude, p.Longitude));
                marker.IsHitTestVisible = false;
                marker.Radius = 5;
                marker.Fill = new SolidBrush(Color.DarkRed);
                //将标记添加到图层
                nodeLayer.Markers.Add(marker);
            }

            if (points == null || points.Count() < 3) return;
            GMapPolygon polygon = new GMapPolygon(temp, Guid.NewGuid().ToString());
            polygon.Fill = new SolidBrush(Color.FromArgb(25, Color.Red));
            polygon.Stroke = new Pen(Color.Red, 1);
            nodeLayer.Polygons.Add(polygon);
        }

        GMapMarkerCircle _selectedMarker;
        #endregion

        protected void SetDataGridViewDoubleBuffered(DataGridView dgv)
        {
            Type dgvType = dgv.GetType();
            PropertyInfo pi = dgvType.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
            pi.SetValue(dgv, true, null);
        }

        private void MenuItem_Export_to_Excel_Click(object sender, EventArgs e)
        {
            ExportDataToExcel(this.dataGridView1);
        }

        public void ExportDataToExcel(DataGridView myDGV)
        {
            string path = "";
            using (SaveFileDialog saveDialog = new SaveFileDialog())
            {
                saveDialog.Title = "请选择要导出的位置";
                saveDialog.Filter = "Excel文件| *.xlsx;*.xls";
                saveDialog.ShowDialog();
                path = saveDialog.FileName;
                if (path.IndexOf(":") < 0) return; //判断是否点击取消
                try
                {
                    Thread.Sleep(1000);
                    StreamWriter sw = new StreamWriter(path, false, Encoding.GetEncoding("gb2312"));
                    StringBuilder sb = new StringBuilder();
                    //写入标题
                    for (int k = 0; k < myDGV.Columns.Count; k++)
                    {
                        if (myDGV.Columns[k].Visible)//导出可见的标题
                        {
                            //"\t"就等于键盘上的Tab,加个"\t"的意思是: 填充完后进入下一个单元格.
                            sb.Append(myDGV.Columns[k].HeaderText.ToString().Trim() + "\t");
                        }
                    }
                    sb.Append(Environment.NewLine);//换行
                                                   //写入每行数值
                    for (int i = 0; i < myDGV.Rows.Count - 1; i++)
                    {
                        System.Windows.Forms.Application.DoEvents();
                        for (int j = 0; j < myDGV.Columns.Count; j++)
                        {
                            if (myDGV.Columns[j].Visible)//导出可见的单元格
                            {
                                //注意单元格有一定的字节数量限制,如果超出,就会出现两个单元格的内容是一模一样的.
                                //具体限制是多少字节,没有作深入研究.
                                sb.Append(myDGV.Rows[i].Cells[j].Value?.ToString().Trim() + "\t");
                            }
                        }
                        sb.Append(Environment.NewLine); //换行
                    }
                    sw.Write(sb.ToString());
                    sw.Flush();
                    sw.Close();
                    MessageBox.Show("Export successfully to" + path, "Messege Box", MessageBoxButtons.OK);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        private void Menu_Item_Open_Csv_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.InitialDirectory = @"D:\MyCode\ASU-Project\RailYardNetwork-main";
            openFileDialog.Filter = "Csv files (*.csv)|*.csv|All files (*.*)|*.*";
            openFileDialog.FilterIndex = 2;
            openFileDialog.RestoreDirectory = true;

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                // 获取选定文件的路径
                string filePath = openFileDialog.FileName;
                _vm.ReadFromCsv(filePath);
            }
        }

        private void MenuItem_Save_Click(object sender, EventArgs e)
        {
            string path = "";
            using (SaveFileDialog saveDialog = new SaveFileDialog())
            {
                saveDialog.Title = "请选择要导出的位置";
                saveDialog.Filter = "Csv 文件| *.csv";
                saveDialog.ShowDialog();
                path = saveDialog.FileName;
                if (path.IndexOf(":") < 0) return; //判断是否点击取消
                try
                {
                    using (var writer = new StreamWriter(path))
                    {
                        using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
                        {
                            csv.WriteHeader<YardItem>();
                            csv.NextRecord();
                            foreach (var item in _vm.Yards)
                            {
                                csv.WriteRecord(item);
                                csv.NextRecord();
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }
    }
}
